#pragma once

#include <gtl/type/inner.h>

namespace gtl
{

template<int BlockSize, int BlockCount = 1>
class mempool
{
	struct block 
	{
		block()
		{
			index = 0;
			data[0] = 0;
			next = NULL;
		}

		uint16 index;
		byte data[BlockSize];
		block* next;
	};

public:
	mempool(int block_count = BlockCount)
	{
		init(block_count);
	}

	~mempool()
	{
		clear();
	}

public:
	template<class T>
	T* alloc(int size)
	{
		return (T*)alloc(size);
	}

	void* alloc(int size)
	{
		if(size <= 0)
			return NULL;

		if(m_curr_block == NULL)
			init();

		if(m_curr_block->index + size >= BlockSize)
		{
			if(m_curr_block->next == NULL)
				alloc_block(BlockCount <= 0 ? 1 : BlockCount, m_curr_block);

			m_curr_block = m_curr_block->next;
		}

		byte* data = m_curr_block->data + m_curr_block->index;
		m_curr_block->index += size;

		return data;
	}

	void free(void* p)
	{
	}

	void clear()
	{
		block* blk = m_first_block;
		while(blk != NULL)
		{
			block* tmp = blk;
			blk = blk->next;
			delete tmp;
		}

		m_curr_block = NULL;
		m_first_block = NULL;
	}

protected:
	void init(int block_count = BlockCount)
	{
		if(block_count <= 0)
			block_count = 1;

		m_curr_block = alloc_block(block_count);
		m_first_block = m_curr_block;
	}

	block* alloc_block(int count, block* curr = NULL)
	{
		block* first = NULL;
		for(int i = 0; i < count; ++i)
		{
			block* blk = new block;
			blk->next = NULL;

			if(first == NULL)
				first = blk;
			else if(curr == NULL)
				curr = first;

			if(curr == NULL)
				continue;

			curr->next = blk;
			curr = curr->next;
		}

		return first;
	}

protected:
	block* m_curr_block;
	block* m_first_block;
};

} // end of namespace gtl